<?php
/**
 *------------------------------------------------
 * Author: YYT[QQ:375776626]
 *------------------------------------------------
 */

abstract class Db
{
    //由继承类获取
    protected $fields = array();

    //由继承类获取
    protected $table;

    //由继承类统计
    protected static $countQuery = 0;

    public static function getCountQuery()
    {
        return self::$countQuery;
    }

    protected $config = array(
        'db_type'          => 'mysql',
        'db_dsn'           => '',
        'db_host'          => 'localhost',
        'db_port'          => 3306,
        'db_name'          => '',
        'db_user'          => 'root',
        'db_password'      => '',
        'db_charset'       => 'UTF8',
        'db_long_connect'  => true,
        'db_prefix'        => '',
        'db_prefix_var'    => '@_',
    );

    public function setConfig(array $config)
    {
        if (!empty($config['db_dsn']) && empty($config['db_type'])) {
            $array = explode(':', $config['db_dsn']);
            $config['db_type'] = array_shift($array);
        }
        $this->config = array_merge($this->config, $config);
    }

    public function getType()
    {
        return $this->config['db_type'];
    }

    public static function getInstance()
    {
        throw new Exception(__METHOD__.' [继承类没有定义: getInstance()]');
    }

    abstract public function escapeString($string);
    abstract public function querySql($sql, $method);
    abstract public function setTable($table);
    abstract public function getFields($table);
    abstract public function beginTransaction();
    abstract public function commit();
    abstract public function rollBack();
    abstract public function lastInsertId();
    abstract public function getVersion();

    private function _parseTable($table)
    {
        return str_replace($this->config['db_prefix_var'], $this->config['db_prefix'], $table);
    }

    public function query($sql)
    {
        $sql = $this->_parseTable($sql);
        return $this->querySql($sql, __FUNCTION__);
    }

    private function _parseJoin($join)
    {
        if (is_array($join)) {
            $_join  = join(' LEFT JOIN ', $join);
            return ' LEFT JOIN '.$this->_parseTable($_join);
        }
        return '';
    }

    private function _parseWhere($where)
    {
        if (!$where) return '';
        if (!is_array($where)) return ' WHERE '.$where;

        $space = ' AND ';
        if (isset($where['_space'])) {
            $where['_space'] = strtoupper($where['_space']);
            if ($where['_space'] == 'OR') $space = ' '.$where['_space'].' ';
            unset($where['_space']);
        }
        $result = ' WHERE ';
        $in = '';
        if (is_array($where)) {
            foreach ($where as $key => $value) {
                if (is_array($value)) { //array('id' => array(1,2,3));
                    foreach ($value as $val) $in .= '\''.$this->escapeString($val).'\',';
                    $in = trim($in, ',');
                    $result .= $key.' IN('.$in.')';
                } else if (strpos($key, ' ')) { //array('add_time >'=>'2010-10-1')，条件key中带 > < 符号
                    $result .= $key.' \''.$this->escapeString($value).'\'';
                } else if (substr(trim($value), 0, 1) == '%' && substr(trim($value), -1) == '%') { //LIKE '%value%'
                    $result .= $key.' LIKE \''.$this->escapeString($value).'\'';
                } else {
                    $result .= $key.' = \''.$this->escapeString($value).'\'';
                }
                $result .= ' '.$space.' ';
            }
            $result = rtrim($result, $space.' ');
        } else {
            return $result.$where;
        }
        return $result;
    }

    private function _parseField($field)
    {
        $field = !$field ? '*' : trim($field);
        if (substr($field, 0, 2) == '!=') {
            $field = substr($field, 2);
            $array = explode(',', $field);
            $fields = ','.join(',', $this->fields).',';
            foreach ($array as $_field) $fields = str_replace(','.$_field.',', ',', $fields);
            return trim($fields, ',');
        }
        return $field;
    }

    private static function _parseOrder($order)
    {
        return trim($order) ? ' ORDER BY '.$order : '';
    }

    private static function _parseLimit($limit)
    {
        return trim($limit) ? ' LIMIT '.$limit : '';
    }

    private $_args = array('field' => '', 'where' => '', 'order' => '', 'limit' => '', 'table' => '', 'alias' => '', 'join' => '');

    public function __call($method, $args)
    {
        $method = strtolower($method);
        if (array_key_exists($method, $this->_args)) {
            if ($method == 'join') {
                $this->_args['join'][] = $args[0];
            } else {
                $this->_args[$method] = $args[0];
            }
        } else {
            throw new Exception(__METHOD__.'调用'.get_class($this).'::'.$method.'不存在');
        }
        return $this;
    }

    protected function getArgs()
    {
        $args = $this->_args;
        $this->_args = array('field' => '', 'where' => '', 'order' => '', 'limit' => '', 'table' => '', 'alias' => '', 'join' => '');
        return $args;
    }

    private function _getTable($args)
    {
        $table = trim($args['table']) ? $this->config['db_prefix'].$args['table'] : $this->table;
        if (Web::config('debug')) {
            $fields = $this->getFields($table);
            if ($fields) {
                Web::debug('表<b>'.$table.'</b>结构: '.join(',', $fields), 2);
            }
        }
        if (trim($args['alias'])) $table .= ' '.$args['alias'];
        return $table;
    }

    public function fetch($pk = '')
    {
        $args = $this->getArgs();
        $table = $this->_getTable($args);
        $field = $this->_parseField($args['field']);
        $where = !$pk ? $this->_parseWhere($args['where'])
            : ' WHERE '.$this->fields['pk'].' = \''.$this->escapeString($pk).'\'';
        $join = $this->_parseJoin($args['join']);
        $order = self::_parseOrder($args['order']);
        $sql = 'SELECT '.$field.' FROM '.$table.$join.$where.$order.' LIMIT 1';
        return $this->querySql($sql, __FUNCTION__);
    }

    public function fetchAll()
    {
        $args = $this->getArgs();
        $table = $this->_getTable($args);
        $field = $this->_parseField($args['field']);
        $where = $this->_parseWhere($args['where']);
        $join = $this->_parseJoin($args['join']);
        $order = self::_parseOrder($args['order']);
        $limit = self::_parseLimit($args['limit']);
        $sql = 'SELECT '.$field.' FROM '.$table.$join.$where.$order.$limit;
        return $this->querySql($sql, __FUNCTION__);
    }

    public function count()
    {
        $args = $this->getArgs();
        $table = $this->_getTable($args);
        $field = trim($args['field']) ? $args['field'] : $this->fields['pk'];
        $where = $this->_parseWhere($args['where']);
        $join = $this->_parseJoin($args['join']);
        $sql = 'SELECT COUNT('.$field.') FROM '.$table.$join.$where;
        return $this->querySql($sql, __FUNCTION__);
    }

    /*
     * 过滤数组数据库中不存在的字段
     * @param array
     * @param string 该参数仅供本类使用
     * @return array
     */
    public function formatData($data, $table = '')
    {
        $result = array();
        if (is_array($data)) {
            $table = trim($table) ? $table : $this->table;
            $fields = $this->getFields($table);
            foreach ($data as $field => $value) {
                if (in_array($field, $fields)) $result[$field] = $value;
            }
        }
        return $result;
    }

    public function insert($data)
    {
        $args = $this->getArgs();
        $table = $this->_getTable($args);
        $data = $this->formatData($data, $table);
        $fields = $values = array();
        foreach ($data as $field => $value) {
            $fields[] = '`'.$field.'`';
            $values[] = '\''.$this->escapeString($value).'\'';
        }

        $field = $fields ? join(',', $fields) : '';
        $value = $values ? join(',', $values) : '';
        if (!$field) return 0; //如果字段全部为空就直接返回
        $sql = 'INSERT INTO '.$table.' ('.$field.') VALUES ('.$value.')';
        return $this->querySql($sql, __FUNCTION__);
    }

    public function update($data)
    {
        $args = $this->getArgs();
        $table = $this->_getTable($args);
        $where = $this->_parseWhere($args['where']);
        if (!$where) return 0; //如果不存在修改条件直接返回
        $value = '';
        if (is_array($data)) {
            $data = $this->formatData($data, $table);
            $values = array();
            foreach ($data as $field => $value) {
                $values[] = '`'.$field.'` = \''.$this->escapeString($value).'\'';
            }
            if ($values) $value = join(',', $values);
        } else {
            $value = $data;
        }
        $sql = 'UPDATE '.$table.' SET '.$value.$where;
        return $this->querySql($sql, __FUNCTION__);
    }

    public function delete($null = '')
    {
        $args = $this->getArgs();
        $table = $this->_getTable($args);
        $sql = 'DELETE FROM '.$table;
        if (!is_null($null)) {
            $where = $this->_parseWhere($args['where']);
            $limit = self::_parseLimit($args['limit']);
            if (!$where && !$limit) return 0; //如果不存在删除条件直接返回
            $order = self::_parseOrder($args['order']);
            $sql .= $where.$order.$limit;
        }
        return $this->querySql($sql, __FUNCTION__);
    }
}